package com.example.readerapp.myandserver.util;

import com.itextpdf.html2pdf.HtmlConverter;
import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.canvas.parser.PdfTextExtractor;
import com.itextpdf.kernel.pdf.canvas.parser.filter.TextRegionEventFilter;
import com.itextpdf.kernel.pdf.canvas.parser.listener.FilteredTextEventListener;
import com.itextpdf.kernel.pdf.canvas.parser.listener.LocationTextExtractionStrategy;
import com.itextpdf.text.*;
import com.itextpdf.text.Font;
import com.itextpdf.text.pdf.*;
import com.itextpdf.text.pdf.parser.*;
import org.apache.pdfbox.io.MemoryUsageSetting;
import org.apache.pdfbox.multipdf.PDFMergerUtility;
import org.apache.pdfbox.multipdf.Splitter;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.docx4j.Docx4J;
import org.docx4j.fonts.IdentityPlusMapper;
import org.docx4j.fonts.Mapper;
import org.docx4j.fonts.PhysicalFonts;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.fit.pdfdom.PDFDomTree;
import org.fit.pdfdom.PDFDomTreeConfig;

import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class PdfUtil
{
    public static ExtractTextFromWebNovelSave extractTextFromWebNovelSave=new ExtractTextFromWebNovelSave();
    public static ExtractTextFromOtherNum_1 extractTextFromOtherNum_1=new ExtractTextFromOtherNum_1();
    public static ExtractTextCommon extractTextCommon=new ExtractTextCommon();
    private static final SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
    /**
     *     String s1=PdfUtil.extractTextFromPdf(PdfUtil.extractTextFromWebNovelSave,"E:\\桌面\\其他\\其他\\英语学习资料\\小说\\中译英\\vipnovel.com等网站\\im-a-spider-so-what_转生成蜘蛛又怎么样.pdf",2);
     *
     * 针对不同的pdf文件设计针对性的pdf文字提取方法
     *
     * */
    public static String extractTextFromPdf(ExtractTextFromPdf extractTextFromPdf,String src,int pageNumber)
    {
        try
        {
            return extractTextFromPdf.extractText(src,pageNumber);
        }
        catch (Exception e)
        {
            System.out.println("提取文字失败");
            e.printStackTrace();
        }
        return "提取pdf文字失败";
    }
   /**提取pdf中的文字，尽量做到一个文字一行*/
    public interface ExtractTextFromPdf{
         String extractText(String src,int pageNumber) throws Exception;
    }
    /**
     *
     * 粗略的对从CommonWebNovelSaveUtil得到的pdf文件进行文字提取
     * PdfUtil.extractText("C:\\Users\\ASUS\\Desktop\\其他\\英语学习资料\\2019考研英语（一)真题.pdf",1);
     * 可以粗略的区分段落，不保证不会发生缺失、多余字符
     *一段一行，"\n"区分
     * 提取pdf文字的操作和目标pdf文件的结构高度相关，本函数只能大致CommonWebNovelSaveUtil.java保存的小说pdf中的文字进行提取
     * 一般性的pdf文件提取推荐PdfUtil.getPdfPageText()函数
     * */
    public static class ExtractTextFromWebNovelSave implements ExtractTextFromPdf{
        /**
         * @param src pdf文件地址
         * @param pageNumber 提取那一页，1开始
         * */
        @Override
        public  String extractText(String src,int pageNumber) throws  Exception
        {
            try
            {
                List<String> text=new ArrayList<>();
                com.itextpdf.text.pdf.PdfReader reader = new com.itextpdf.text.pdf.PdfReader(src);
                RenderListener listener
                        = new MyTextRenderListener(text);
                PdfContentStreamProcessor processor
                        = new PdfContentStreamProcessor(listener);
                PdfDictionary pageDic = reader.getPageN(pageNumber);
                PdfDictionary resourcesDic
                        = pageDic.getAsDict(PdfName.RESOURCES);
                processor.processContent(ContentByteUtils
                                                 .getContentBytesForPage(reader, pageNumber), resourcesDic);
                reader.close();
                String result="";
                for(int i=0;i< text.size();)
                {
                    //当一个不为空格的元素(A)的下一个元素为空格时，表示下下个元素和A是同一段落
                    //System.out.println("一行："+text.get(i));
                    String passage=text.get(i);
                    int j=i+1;
                    for(;j<text.size();)
                    {
                        if(text.get(j).equals(" ")||text.get(j).equals(" "))
                        {
                            j=j+1;
                            if(j< text.size())
                                passage=passage+" "+text.get(j);
                            j=j+1;
                        }
                        else
                            break;
                    }
                    i=j;
                    result=result+"\n"+passage;
                }
                return result;
            }catch (Exception e)
            {
                System.out.println("提取文字失败");
                e.printStackTrace();
            }
            return "提起pdf文字失败";
        }
        private static class MyTextRenderListener implements RenderListener {
            //protected PrintWriter out;
            protected List<String> text;
            int count=1;
            public MyTextRenderListener(List<String> text) {
                this.text=text;
                // this.out = out;
            }
            public void beginTextBlock() {
                //System.out.println("第"+count+"个开始");
            }
            public void endTextBlock() {
                //System.out.println("第"+count+"个结束");
                //count++;
            }
            public void renderImage(ImageRenderInfo renderInfo) {
            }
            public void renderText(TextRenderInfo renderInfo) {
                text.add(renderInfo.getText());
                //System.out.println("@"+renderInfo.getText()+"@");
            }

        }
    }
    /**
     * String s1=PdfUtil.extractTextFromPdf(PdfUtil.extractTextFromOtherNum_1,"E:\\桌面\\其他\\1_Homeland.pdf",9);
     *
     * 针对一些其他格式的pdf的文字提取
     * 没有发现如何完全正确的区分段落
     * */
    static class ExtractTextFromOtherNum_1 implements ExtractTextFromPdf{
        /**
         *
         * @param src pdf文件地址
         * @param pageNumber 提取那一页，1开始
         * */
        @Override
        public  String extractText(String src,int pageNumber) throws  Exception
        {
            try
            {
                List<String> text=new ArrayList<>();
                com.itextpdf.text.pdf.PdfReader reader = new com.itextpdf.text.pdf.PdfReader(src);
                RenderListener listener
                        = new MyTextRenderListener_1(text);
                PdfContentStreamProcessor processor
                        = new PdfContentStreamProcessor(listener);
                PdfDictionary pageDic = reader.getPageN(pageNumber);
                PdfDictionary resourcesDic
                        = pageDic.getAsDict(PdfName.RESOURCES);
                processor.processContent(ContentByteUtils
                                                 .getContentBytesForPage(reader, pageNumber), resourcesDic);
                reader.close();
                String result="";
                for(int i=0;i< text.size();i++)
                {
                    result=result+text.get(i);
                }
                return result.replaceAll("\t"," ");
            }catch (Exception e)
            {
                System.out.println("提取文字失败");
                e.printStackTrace();
            }
            return "提起pdf文字失败";
        }
        private class MyTextRenderListener_1 implements RenderListener {
            protected List<String> text;
            int count=1;
            public MyTextRenderListener_1(List<String> text) {
                this.text=text;
            }
            public void beginTextBlock() {
             //   System.out.println("第"+count+"个开始");
            }
            public void endTextBlock() {
                //System.out.println("第"+count+"个结束");//一般是一行的结束
                String end=text.get(text.size()-1);
                text.add(" ");
                String[] flagsEnd={".","\"","?","!","'","。","？","！","”","’"};//认为在一行的结尾出现这些字符，那么认为这是一个段落的结尾
                for(int i=0;i< flagsEnd.length;i++)
                {
                    if(end.equals(flagsEnd[i]))
                    {
                        text.add("\n");
                        break;
                    }
                }

              //  count++;
            }
            public void renderImage(ImageRenderInfo renderInfo) {
            }
            public void renderText(TextRenderInfo renderInfo) {
                text.add(renderInfo.getText());
              //  System.out.println("@"+renderInfo.getText()+"@");
            }

        }
    }

    /*提取的大部分文字都没有问题，但不保证段落划分正确*/
    static class ExtractTextCommon implements ExtractTextFromPdf
    {
        /**
         * itext框架：获取pdf文件指定页的文字,得到的格式可能有问题，和源文件自身有关，无法完美区分段落
         * @param src pdf路径
         * @param pageNum 获取第几页的文字
         * */
        @Override
        public  String extractText(String src,int pageNum) throws Exception
        {
            PdfDocument pdfDocument=new PdfDocument(new PdfReader(src));
            try
            {
                float height = pdfDocument.getPage(pageNum).getPageSize().getHeight();
                float width = pdfDocument.getPage(pageNum).getPageSize().getWidth();
                Rectangle rect = new Rectangle(width, height);
                FilteredTextEventListener filterListener = new FilteredTextEventListener(new LocationTextExtractionStrategy(), new TextRegionEventFilter(rect));
                //FilteredTextEventListener filtered_Test=new FilteredTextEventListener(new FilteredTextEventListener(),new TextRegionEventFilter(rect));
                String extractedText = PdfTextExtractor.getTextFromPage(pdfDocument.getPage(pageNum), filterListener);

                String result=splitPassage(extractedText);
                pdfDocument.close();
                return result;
            }catch (Exception e)
            {
                pdfDocument.close();
                System.out.println("提取pdf文字失败");
                e.printStackTrace();
            }
            finally
            {
                pdfDocument.close();

            }
            return "提取pdf文字失败";
        }

        private String splitPassage(String text)
        {
            char[] line=text.toCharArray();
            String result="";
            for(int i=0;i<line.length;i++)
            {
                if(line[i]=='\n')
                {
                    if (i-1>=0&&i+1<line.length)
                    {
                        if((line[i+1]>='a'&&line[i+1]<='z')||(line[i+1]==' ')||(line[i-1]==' ')||(line[i-1]>='a'&&line[i-1]<='z')||line[i-1]==',')
                        {
                            line[i]=' ';//认为与上一行为同一段落
                        }
                    }
                }
                result=result+line[i];
            }
            return result;
        }
    }

    /**
     * 使用itextpdf框架将PDF文件切分成多个PDF，可以切分比较大的文件
     *
     * @param filePath  pdf文件路径 参考值："C:\\Users\\ASUS\\Desktop\\其他\\英语学习资料\\小说\\中译英\\vipnovel.com等网站\\forty-millenniums-of-cultivation_修真四万年.pdf"
     * @param savePath 切分结果保存路径 参考值：D:\\JAVA代码\\UtilDEV\\src\\main\\resources\\temp\\pdf\\"
     * @param splitSize 拆分单个文件页数(1表示拆分成多个pdf，每个pdf一页) 参考值： 1
     */
    public static void splitPdf(String filePath,String savePath, int splitSize) throws Exception {
        System.out.println(simpleDateFormat.format(new Date())+":开始切分pdf");
        com.itextpdf.text.pdf.PdfReader reader;
        try {
            reader = new com.itextpdf.text.pdf.PdfReader(filePath);
        } catch (IOException e) {
            e.printStackTrace();
            throw new Exception("读取PDF文件失败");
        }
        int numberOfPages = reader.getNumberOfPages();
        int newFileCount = 1;
        // PageNumber是从1开始计数的
        int pageNumber = 1;
        while (pageNumber <= numberOfPages) {
            Document doc = new Document();
            String splitFileName = savePath+newFileCount+".pdf";
            PdfCopy pdfCopy;
            try {
                pdfCopy = new PdfCopy(doc, new FileOutputStream(splitFileName));
            } catch (FileNotFoundException | DocumentException e) {
                e.printStackTrace();
                throw new Exception("切割文件副本创建失败");
            }
            doc.open();
            // 将pdf按页复制到新建的PDF中
            for (int i = 1; pageNumber <= numberOfPages && i <= splitSize; ++i, pageNumber++) {
                doc.newPage();
                PdfImportedPage page = pdfCopy.getImportedPage(reader, pageNumber);
                pdfCopy.addPage(page);
            }
            doc.close();
            newFileCount++;
            pdfCopy.close();
        }
        reader.close();
        System.out.println(simpleDateFormat.format(new Date())+":结束切分pdf");
    }
}
